#ifndef _WAVE_CODEC_H_
#define _WAVE_CODEC_H_

#include <mcus/phy62xx/std_type.h>

#include "stdc.h"
#include "std_err.h"
#include "mcu.h"
#include "qchar.h"

#ifdef __cplusplus
extern "C" {
#endif


// 以大端模式表示的 trunk 标识
#define TRUNK_ID_RIFF 0x52494646 // "RIFF"
#define TRUNK_ID_WAVE 0x57415645 // "WAVE"
#define TRUNK_ID_FMT  0x666D7420 // "fmt "
#define TRUNK_ID_FACT 0x66616374 // "fact"
#define TRUNK_ID_DATA 0x64617461 // "data"
#define TRUNK_ID_LIST 0x4C495354 // "LIST"

/// 音频编码格式
typedef enum {
	FMT_PCM			= 0x0001, 	///< 原始PCM
	FMT_ADPCM_MS 	= 0x0002, 	///< ADPCM-MS
	FMT_A_LAW 		= 0x0006,	///< ITU G.711 a-law
	FMT_U_LAW 		= 0x0007,	///< ITU G.711 u-law
	FMT_ADPCM_IMA	= 0x0011,	///< ADPCM-IMA
	FMT_ADPCM_G721	= 0x0064, 	///< ITU G.721 ADPCM
	FMT_EXT			= 0xFFFE, 	///< 见子格式块中的编码格式
} audio_format_t;

#pragma pack(push, 1)

/// trunk 通用数据结构
typedef struct {
	uint32_t ID;						///< (大端)块标识
	uint32_t trunkSize;				///< (小端)本区块长度-8(不含 ID 及 trunkSize 本身)
	uint8_t data[4];					///< 块数据区(一般最少4字节)
} trunk_t;

/// RIFF 块数据结构
typedef struct {
	uint32_t ID;						///< (大端)0x52494646 / "RIFF"
	uint32_t fileSize;				///< (小端)文件长度-8(不含 ID 及 fileSize 本身)
	uint32_t WAVE;					///< (大端)0x57415645 / "WAVE"
} riff_trunk_t;

/// fmt 块数据结构
typedef struct {
	uint32_t ID;						///< (大端)0x666D7420 / "fmt "
	uint32_t trunkSize;				///< (小端)本区块长度-8(不含 ID 及 trunkSize 本身)
	uint16_t audioFormat;			///< (小端)音频格式，见 audio_format_t
	uint16_t nChannels;				///< (小端)声道数量
	uint32_t sampleRate;				///< (小端)采样速率
	uint32_t byteRate;				///< (小端)编码速率
	uint16_t blockAlign;				///< (小端)数据块对齐
	uint16_t bitsPerSample;			///< (小端)采样位数
	
	// 扩展格式(应根据 trunkSize 判断是否存在)
	uint16_t subFormatSize;			///< 子格式块大小
	union {
		struct {
			// IMA-ADPCM 一般多出2个字节，也就是nSamplesPerBlock
			uint16_t samplesPerBlock;	///< 每个块中采样点的数量
		} adpcm_ima;
	} ext;
} format_trunk_t;

#pragma pack(pop)

/// wave 文件解析、解码、播放运行时数据结构
typedef struct st_wave_runtime_t {
	// wave 文件信息
	uint16_t audioFormat;			///< 音频格式，见 audio_format_t
	uint16_t nChannels;				///< 声道数量
	uint32_t sampleRate;				///< 采样速率
	uint16_t blockAlign;				///< 数据块对齐
	uint16_t blockCount;				///< 数据块数量
	uint16_t bitsPerSample;			///< (小端)采样位数
	uint16_t samplesPerBlock;		///< 每个块中采样点的数量
	uint32_t sampleCount;			///< 采样点数量
	const void *firstBlock;		///< 第一个数据块指针
	
	// 解码及播放时需要的数据结构
	uint16_t currentBlock;			///< 当前已经处理的数据块数量；如果为blockCount，表示已经处理完成
	QChar *samplesQueue; 		///< 当前已经解码出来的采样点循环队列
	
	// 播放状态
	uint8_t volume;					///< 播放音量
	uint8_t repeat;					///< 播放循环次数
	OSTaskId decodeTaskId;		///< 解码循环任务ID
	uint32_t playedSamples;			///< 已经播放的采样点数量(播放进度)
	
	/// 播放完成时回调函数
	void (*playCompleteCallback)(struct st_wave_runtime_t *wave);
} wave_runtime_t;

/// wave 文件播放完成时回调函数原型
typedef void (*FUNC_play_wave_complete)(wave_runtime_t *wave);

/// 获取下一个 trunk 信息
const trunk_t* wave_codec_get_next_trunk(const void *fileData, uint32_t fileLen, const trunk_t *prevTrunk);
/// 获取 wave 文件信息
std_err_t wave_codec_parse_file(const void *fileData, uint32_t fileLen, /*out*/wave_runtime_t *info);
/// 解码
std_err_t wave_codec_decode(wave_runtime_t *info);


#ifdef __cplusplus
}
#endif

#endif //_WAVE_CODEC_H_
